package tests;

import java.lang.reflect.Method;
import java.util.ArrayList;

import tester.*;

@Example
public class SuperclassTests {
	
	private Method[] findAllMethods(Class<?> c){
		Class<?> classToSurvey = c;
		
		ArrayList<Method> list = new ArrayList<Method>();
		while (classToSurvey != null  && classToSurvey != Object.class) {
			Method[] allMethods = classToSurvey.getDeclaredMethods();
			for (Method m : allMethods) {
				m.setAccessible(true);
				list.add(m);
			}
			
			classToSurvey = classToSurvey.getSuperclass();
		}

		return list.toArray(new Method[0]);
	}
	
	@TestMethod
	public void testFindAll(Tester t){
		//Collect all the methods for the class BarSub
		Method[] allFound = findAllMethods(BarSub.class);
		
		//For each method we found
		int i = 0;
		for(Method m : allFound){
		    FooSuper fs1 = new BarSub();
		    FooSuper fs2 = new FooSuper();
			try {
					/*
					  Invoke the method with a zero argument constructor
					  and then check to see if the return type was not null
					  and was an Integer.  If it was, check to see that the
					  methods (and we're checking both the base and super 
					  class version) return one, even though FooSuper 
					  would appear to return zero at first glance.
					*/
					Object o1 = m.invoke(fs1, new Object[0]);
					if(o1 != null && o1.getClass() == Integer.class){
						Integer temp = (Integer) o1;
						t.checkExpect(temp, 1, "Iteration: " + i
								+ "\n Instance of BarSub\n" +
								m.toString());
					}
					Object o2 = m.invoke(fs2, new Object[0]);
					if(o2 != null && o2.getClass() == Integer.class){
						Integer temp = (Integer) o2;
						t.checkExpect(temp, 0, "Iteration: " + i + "\n" +
								"Instance of FooSuper\n"
								+ m.toString());
					}
			} catch (Throwable throwable) {
				t.success("Failure at iteration i: " 
						+ i + "\n" + throwable.getMessage()
						+ "\nMethod:\n" + m.toString());
			}finally{
				i++;
			}
		}	
	}
	
	public static void main(String[] args){
		Tester.runFullReport(new SuperclassTests());
	}

}

class FooSuper{
	
	public FooSuper(){}
	
	public void randomMethod(){}
	
	public int anotherThing() { return 0; }
}

class BarSub extends FooSuper{
	
	public BarSub(){}
	
	public void fooBar(){}
	
	public int anotherThing() { return 1; }
}
